package world

import org.apache.shiro.authz.AuthorizationException
import org.apache.shiro.cache.CacheManager
import org.apache.shiro.cache.MemoryConstrainedCacheManager
import org.apache.shiro.realm.Realm
import org.apache.shiro.realm.jdbc.JdbcRealm
import org.apache.shiro.realm.text.TextConfigurationRealm
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.cache.annotation.EnableCaching
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.ComponentScan
import org.springframework.http.HttpStatus
import org.springframework.scheduling.annotation.EnableScheduling
import org.springframework.transaction.annotation.EnableTransactionManagement
import org.springframework.ui.Model
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.ResponseBody
import org.springframework.web.bind.annotation.ResponseStatus
import org.springframework.web.servlet.config.annotation.CorsRegistry
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer

import javax.sql.DataSource

@ComponentScan(['world','asset.pipeline.springboot'])
@SpringBootApplication
@EnableTransactionManagement
@EnableCaching
@EnableScheduling
class GradleWebApplication {

    @Autowired
    private DataSource dataSource //mybatis-spring-boot-starter支持

	static void main(String[] args) {
		SpringApplication.run GradleWebApplication, args
	}

    @Bean
    Realm realm() { //存储有效Subject（“访客”）身份权限信息的仓库
        JdbcRealm realm = new JdbcRealm()
        realm.setDataSource(dataSource) //依赖注入

        realm.setPermissionsLookupEnabled(true) //开启权限查询，使PermissionsQuery可用
        realm.setAuthenticationQuery("select password from user where username = ?") //用户（users -> user）
        realm.setUserRolesQuery("select role_name from user_roles where username = ?") //角色（默认）
        realm.setPermissionsQuery("select permission from roles_permissions where role_name = ?") //权限（默认）

        realm.setCachingEnabled(true)
        return realm
    }

    @Bean
    ShiroFilterChainDefinition shiroFilterChainDefinition() { //Shiro Filter过滤器，原则上，所有Web请求都必须通过滤器
        /* 默认过滤器（DefaultFilter）
        anon(AnonymousFilter.class)，指定url可以匿名访问
        authc(FormAuthenticationFilter.class)，指定url需要form表单登录，默认会从请求中获取username、password、rememberMe等参数并尝试登录，如果登录不了就会跳转到loginUrl配置的路径
        authcBasic(BasicHttpAuthenticationFilter.class)，指定url需要basic登录
        logout(LogoutFilter.class)，登出过滤器，配置指定url就可以实现退出功能
        noSessionCreation(NoSessionCreationFilter.class)，禁止创建会话
        perms(PermissionsAuthorizationFilter.class)，需要指定权限才能访问
        port(PortFilter.class)，需要指定端口才能访问
        rest(HttpMethodPermissionFilter.class)，将http请求方法转化成相应的动词来构造一个权限字符串
        roles(RolesAuthorizationFilter.class)，需要指定角色才能访问
        ssl(SslFilter.class)，需要https请求才能访问
        user(UserFilter.class)，需要已登录或“记住我”的用户才能访问*/

        def chainDefinition = new DefaultShiroFilterChainDefinition()
        chainDefinition.addPathDefinition("/login", "authc") //进行form表单登录（特殊）
        chainDefinition.addPathDefinition("/logout", "logout") //退出登录（特殊）
        chainDefinition.addPathDefinition("/**", "anon") //为URL路径指定过滤器，简单理解，为URL路径设定访问权限（anon，AnonymousFilter，匿名访问）。那么，本句话的意思可简单理解为，将所有URL路径的访问权限（/**）都设定为可匿名访问（anon）-> 注解
        return chainDefinition
    }

    @Bean
    protected CacheManager cacheManager() { //缓存管理
        return new MemoryConstrainedCacheManager()
    }

    @Bean
    static DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() { //解决“AspectJ”与“Shiro注解”一起使用时出现的404问题
        def defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator()
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true)
        return defaultAdvisorAutoProxyCreator
    }

    @Bean
    WebMvcConfigurer webMvcConfigurer() { //解决react跨域问题
        return new WebMvcConfigurer() {
            @Override
            void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**").allowedMethods("*").allowedOrigins("http://localhost:3000", "http://localhost:8000")
            }
        }
    }

}
